/*
 * proc_mgmt.h
 *
 *  Created on: 15-May-2011
 *      Author: tan-ce
 */

#ifndef PROC_MGMT_H_
#define PROC_MGMT_H_

#include <unistd.h>
#include <cstring>
#include <string>
#include <errno.h>
#include <exception>
#include <signal.h>
#include <sys/wait.h>

#include "tcetools/socket.h"

namespace tcetools {

class ChildProcess {
protected:
	int fd_in;
	int fd_out;
	int fd_err;

	Socket *s_out;
	Socket *s_err;
	Socket *s_in;

	pid_t child_pid;

	int ret_status;

	void init();
public:
	ChildProcess(const char *path, char *const argv[]) {
		init();
		if (is_child()) exec_cmd(path, argv);
	}

	ChildProcess(const char *cmd);

	ChildProcess() {
		init();
	}

	~ChildProcess();

	static void exec_cmd(const char *path, char *const argv[]);

	Socket &in() { return *s_in; }
	Socket &out() { return *s_out; }
	Socket &err() { return *s_err; }

	pid_t get_pid() { return child_pid; }
	bool is_parent() { return (child_pid > 0); }
	bool is_child() { return (child_pid == 0); }

	bool is_alive(){
		return !(waitpid(child_pid, &ret_status, WNOHANG) == child_pid);
	}

	bool is_terminated_normally() { return WIFEXITED(ret_status); }
	int get_return_code() { return WEXITSTATUS(ret_status); }
};

////////////////////////////////////////////////////////////////////////////////

class ProcessError : public std::exception {
protected:
	int unix_errno;
	std::string msg;

public:
	ProcessError(const char *msg) {
		this->msg = msg;
		unix_errno = errno;
	}

	virtual ~ProcessError() throw () {}

	void append_unix_error() {
		msg.append(" (");
		msg.append(strerror(errno));
		msg.append(")");
	}

	int get_unix_errno() { return unix_errno; }
	virtual const char* what() const throw() {
		return msg.c_str();
	}
};

} // namespace tcetools

#endif /* PROC_MGMT_H_ */
